jetcrab\bytecode\statements/
loop_statements.rs1use crate::ast::Node;
2use crate::vm::instructions::Instruction;
3use crate::vm::types::CodeAddress;
4
5use super::ControlFlowCore;
6
7pub fn generate_for_statement<T>(this: &mut T, node: &Node)
8where
9 T: ControlFlowCore,
10{
11 if let Node::ForStatement(stmt) = node {
12 if let Some(init) = &stmt.init {
14 this.visit_node(init);
15 }
16
17 let loop_start = this.instructions().len();
19
20 if let Some(test) = &stmt.test {
22 this.visit_node(test);
23
24 let jump_out_pos = this.instructions().len();
26 this.instructions()
27 .push(Instruction::JumpIfFalse(CodeAddress::new(0))); this.visit_node(&stmt.body);
31
32 if let Some(update) = &stmt.update {
34 this.visit_node(update);
35 }
36
37 this.instructions()
39 .push(Instruction::Jump(CodeAddress::new(loop_start)));
40
41 let loop_end = this.instructions().len();
43
44 this.instructions()[jump_out_pos] =
46 Instruction::JumpIfFalse(CodeAddress::new(loop_end));
47
48 for i in loop_start..loop_end {
50 if let Instruction::Jump(addr) = &this.instructions()[i] {
51 if addr.as_usize() == 9999 {
52 this.instructions()[i] = Instruction::Jump(CodeAddress::new(loop_end));
53 }
54 }
55 }
56
57 let continue_target = if let Some(_) = &stmt.update {
60 loop_start
64 } else {
65 loop_start
67 };
68
69 for i in loop_start..loop_end {
70 if let Instruction::Jump(addr) = &this.instructions()[i] {
71 if addr.as_usize() == 8888 {
72 this.instructions()[i] = Instruction::Jump(CodeAddress::new(continue_target));
73 }
74 }
75 }
76 } else {
77 this.visit_node(&stmt.body);
79
80 if let Some(update) = &stmt.update {
82 this.visit_node(update);
83 }
84
85 this.instructions()
87 .push(Instruction::Jump(CodeAddress::new(loop_start)));
88 }
89 }
90}
91
92pub fn generate_while_statement<T>(this: &mut T, node: &Node)
93where
94 T: ControlFlowCore,
95{
96 if let Node::WhileStatement(stmt) = node {
97 let loop_start = this.instructions().len();
99
100 let is_true_literal = matches!(&*stmt.test, Node::Boolean(true));
102
103 let jump_out_pos = if !is_true_literal {
104 this.visit_node(&stmt.test);
106
107 let pos = this.instructions().len();
109 this.instructions()
110 .push(Instruction::JumpIfFalse(CodeAddress::new(0))); Some(pos)
112 } else {
113 None
115 };
116
117 this.visit_node(&stmt.body);
119
120 this.instructions()
122 .push(Instruction::Jump(CodeAddress::new(loop_start)));
123
124 let loop_end = this.instructions().len();
126
127 if let Some(jump_pos) = jump_out_pos {
129 this.instructions()[jump_pos] =
130 Instruction::JumpIfFalse(CodeAddress::new(loop_end));
131 }
132
133 for i in loop_start..loop_end {
135 if let Instruction::Jump(addr) = &this.instructions()[i] {
136 if addr.as_usize() == 9999 {
137 this.instructions()[i] = Instruction::Jump(CodeAddress::new(loop_end));
138 }
139 }
140 }
141
142 let continue_target = if !is_true_literal {
145 loop_start
147 } else {
148 loop_start
150 };
151
152 for i in loop_start..loop_end {
153 if let Instruction::Jump(addr) = &this.instructions()[i] {
154 if addr.as_usize() == 8888 {
155 this.instructions()[i] = Instruction::Jump(CodeAddress::new(continue_target));
156 }
157 }
158 }
159 }
160}
161
162pub fn generate_do_while_statement<T>(this: &mut T, node: &Node)
163where
164 T: ControlFlowCore,
165{
166 if let Node::DoWhileStatement(stmt) = node {
167 let loop_start = this.instructions().len();
169
170 this.visit_node(&stmt.body);
172
173 this.visit_node(&stmt.test);
175
176 this.instructions()
178 .push(Instruction::JumpIfTrue(CodeAddress::new(loop_start)));
179
180 let loop_end = this.instructions().len();
182
183 for i in loop_start..loop_end {
185 if let Instruction::Jump(addr) = &this.instructions()[i] {
186 if addr.as_usize() == 9999 {
187 this.instructions()[i] = Instruction::Jump(CodeAddress::new(loop_end));
188 }
189 }
190 }
191
192 for i in loop_start..loop_end {
195 if let Instruction::Jump(addr) = &this.instructions()[i] {
196 if addr.as_usize() == 8888 {
197 let test_start = loop_start + 1; this.instructions()[i] = Instruction::Jump(CodeAddress::new(test_start));
200 }
201 }
202 }
203 }
204}
205
206pub fn generate_for_in_statement<T>(this: &mut T, node: &Node)
207where
208 T: ControlFlowCore,
209{
210 if let Node::ForInStatement(stmt) = node {
211 this.visit_node(&stmt.left);
214 this.visit_node(&stmt.right);
215 this.visit_node(&stmt.body);
216 }
217}
218
219pub fn generate_for_of_statement<T>(this: &mut T, node: &Node)
220where
221 T: ControlFlowCore,
222{
223 if let Node::ForOfStatement(stmt) = node {
224 this.visit_node(&stmt.left);
227 this.visit_node(&stmt.right);
228 this.visit_node(&stmt.body);
229 }
230}